import { Style, Circle, Fill, Stroke, Icon, Text } from "ol/style";
import { StyleFunction } from "ol/style/Style";
import { Color } from "ol/color";
import { ColorLike, PatternDescriptor } from "ol/colorlike";
import markBlue from "../assets/images/mark_blue.png";
import { resolution2scale } from "../utils/sizeFit";
import { FeatureLike } from "ol/Feature";

export function createStyle(...args: ConstructorParameters<typeof Style>) {
  return new Style(...args);
}

export enum PointType {
  Circle = "circle",
  Image = "image",
}

interface CirclePointStyleOptions {
  type: PointType.Circle;
  color?: Color | ColorLike | PatternDescriptor;
  radius?: number;
}

interface ImagePointStyleOptions {
  type: PointType.Image;
  rotation?: number;
  src?: string;
  anchor?: [number, number];
}

export type PointKindStyle<T extends PointType> = T extends PointType.Circle
  ? CirclePointStyleOptions
  : ImagePointStyleOptions;

export type PointStyleOptions<T extends PointType> = PointKindStyle<T> & {
  scale?: number;
  sizeFit?: boolean;
  styleFunction?: (
    feature: FeatureLike,
    resolution: number,
    style: Style
  ) => ReturnType<StyleFunction>;
};

export function createPointStyle(styleOptions?: PointStyleOptions<PointType>) {
  if (!styleOptions) {
    return createMarkPointStyle();
  }

  if (styleOptions.type === PointType.Circle) {
    return createCirclePointStyle(styleOptions);
  } else if (styleOptions.type === PointType.Image) {
    return createMarkPointStyle(styleOptions);
  }
}

// type StyleFunctionParameters = Parameters<StyleFunction>;
// type StyleFunctionReturnType = ReturnType<StyleFunction>;
// type StyleFunctionType = [...StyleFunctionParameters, Style];

export function createCirclePointStyle(
  styleOptions?: PointStyleOptions<PointType.Circle>
) {
  const image = new Circle({
    radius: styleOptions?.radius || 10,
    scale: styleOptions?.scale || 1,
    fill: new Fill({
      color: styleOptions?.color || "red",
    }),
  });
  let style = createStyle({
    image,
  });

  if (styleOptions?.styleFunction) {
    return (feature: FeatureLike, resolution: number) =>
      styleOptions.styleFunction!(feature, resolution, style);
  }

  if (styleOptions?.sizeFit) {
    return (feature: FeatureLike, resolution: number) => {
      //map.getView().getZoomForResolution(resolution);
      const scalable = feature.get("scalable");
      
      if (scalable === false) {
        return style;
      }
      const scale = resolution2scale(resolution);
      const image = style.getImage() as Circle;
      image.setScale(+scale.toFixed(2));
      style.setImage(image);
      return style;
    };
  }

  return style;
}

export function createMarkPointStyle(
  styleOptions?: PointStyleOptions<PointType.Image>
) {
  const image = new Icon({
    src: styleOptions?.src || markBlue,
    scale: styleOptions?.scale || 1,
    rotation: styleOptions?.rotation || 0,
    anchor: styleOptions?.anchor || [0.5, 1],
  });

  const style = createStyle({
    image,
  });

  if (styleOptions?.styleFunction) {
    return (feature: FeatureLike, resolution: number) =>
      styleOptions.styleFunction!(feature, resolution, style);
  }

  if (styleOptions?.sizeFit) {
    return (feature: FeatureLike, resolution: number) => {
      //map.getView().getZoomForResolution(resolution);
      const scalable = feature.get("scalable");

      if (scalable === false) {
        return style;
      }
      
      const scale = resolution2scale(resolution);
      const image = style.getImage() as Icon;
      image.setScale(+scale.toFixed(2));
      style.setImage(image);
      return style;
    };
  }

  return style;
}
